package cate.game.role.farm;

import cate.common.table.d.*;
import cate.common.table.farm.config.row.FbBuyConsumeRow;
import cate.common.util.GameResult;
import cate.game.activity.taskactivity.RoleTaskActivity;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;

import java.util.HashMap;
import java.util.Map;

@NoteClass(value = "挑战次数记录")
public class PlayTimes {

    public PlayTimes() {
    }

    @NoteField(
            value = "今日已使用de免费挑战次数",
            detail = "Map<支付类型，次数>")
    public Map<Byte, Integer> freeTimes;

    @NoteField(
            value = "今日已购买de挑战次数",
            detail = "Map<支付类型，次数>")
    public Map<Byte, Integer> buyTimes;

    @NoteField(value = "余额，购买但未使用de挑战次数", detail = "不包含免费挑战次数,跨天不清")
    public int balance;

    @NoteField(value = "挑战完后的支付方式", detail = "0未支付 1基本免费 2活动免费 3特权免费 4余额")
    @JsonIgnore
    protected byte affordType;

    public void initialize() {
        if (freeTimes == null) {
            freeTimes = new HashMap<>();
        }
        if (buyTimes == null) {
            buyTimes = new HashMap<>();
        }
    }

    /**
     * 次数重置（不清余额）
     */
    public void reset() {
        freeTimes.clear();
        buyTimes.clear();
    }

    /**
     * 次数重置(包括余额)
     */
    public void resetAll() {
        freeTimes.clear();
        buyTimes.clear();
        balance = 0;
    }

    /**
     * 挑战次数加1
     */
    public void added() {
        if (affordType == GDPlayTime.Afford.BALANCE) {
            if (balance >= 1) {
                balance--;
            }
        } else {
            Integer use = freeTimes.get(affordType);
            if (use == null) {
                use = 0;
            }
            freeTimes.put(affordType, use + 1);
        }
        affordType = GDPlayTime.Afford.FAIL;
    }

    /**
     * 次数是否够用(如果不够用，就会自动购买次数)
     */
    public GameResult<Void> available(Role role, int funcId) {
        GameResult<Void> r;
        // 免费次数检测
        r = checkFree(role, funcId);
        if (r.ok()) {
            return r;
        }
        // 余额检测
        r = checkBalance();
        if (r.ok()) {
            return r;
        }
        // 付费检测
        r = checkBuy(role, funcId);
        if (r.ok()) {
            return r;
        }
        return r;
    }

    /**
     * 检测免费挑战是否可用
     */
    public GameResult<Void> checkFree(Role role, int funcId) {
        GameResult<Void> r;
        r = checkFree(role, funcId, GDPlayTime.Afford.PRIVILEGE);
        if (r.ok()) {
            return r;
        }
        r = checkFree(role, funcId, GDPlayTime.Afford.ACTIVITY);
        if (r.ok()) {
            return r;
        }
        r = checkFree(role, funcId, GDPlayTime.Afford.BASE);
        if (r.ok()) {
            return r;
        }
        return r.fail("免费次数不足");
    }

    /**
     * 检测免费挑战是否可用
     */
    private GameResult<Void> checkFree(Role role, int funcId, byte affordType) {
        GameResult<Void> r = new GameResult<>();
        int available;
        switch (affordType) {
            case GDPlayTime.Afford.BASE:
                available = getBasicFreeTimes(role, funcId);
                break;
            case GDPlayTime.Afford.PRIVILEGE:
                available = getPrivilegeFreeTimes(role, funcId);
                break;
            case GDPlayTime.Afford.ACTIVITY:
                available = getActivityFreeTimes(role, funcId);
                break;
            default:
                available = 0;
        }
        Integer use = freeTimes.get(affordType);
        if (use == null) {
            use = 0;
        }
        if (use < available) {
            this.affordType = affordType;
            return r.success();
        }
        return r.fail();
    }

    @JsonIgnore
    public int getFreeRemain(Role role, int funcId) {
        int total = 0;
        total += getFreeRemain(role, funcId, GDPlayTime.Afford.BASE);
        total += getFreeRemain(role, funcId, GDPlayTime.Afford.ACTIVITY);
        total += getFreeRemain(role, funcId, GDPlayTime.Afford.PRIVILEGE);

        return total;
    }

    @JsonIgnore
    public int getFreeTotal(Role role, int funcId) {
        int total = 0;
        total += getBasicFreeTimes(role, funcId);
        total += getPrivilegeFreeTimes(role, funcId);
        total += getActivityFreeTimes(role, funcId);
        return total;
    }

    private int getFreeRemain(Role role, int funcId, byte affordType) {
        int available;
        switch (affordType) {
            case GDPlayTime.Afford.BASE:
                available = getBasicFreeTimes(role, funcId);
                break;
            case GDPlayTime.Afford.PRIVILEGE:
                available = getPrivilegeFreeTimes(role, funcId);
                break;
            case GDPlayTime.Afford.ACTIVITY:
                available = getActivityFreeTimes(role, funcId);
                break;
            default:
                available = 0;
        }
        Integer use = freeTimes.get(affordType);
        if (use == null) {
            use = 0;
        }
        int remain = available - use;
        if (remain < 0) {
            remain = 0;
        }
        return remain;
    }

    @JsonIgnore
    public int getBuyTotal(Role role, int funcId) {
        int total = 0;
        total += getBasicBuyTimes(role, funcId);
        total += getPrivilageBuyTimes(role, funcId);
        return total;
    }

    @JsonIgnore
    public int getBuyRemain(Role role, int funcId, int buyTime) {
        int total = getBuyTotal(role, funcId) - buyTime;
        return Math.max(total, 0);
    }

    /**
     * 检测余额是否可用
     */
    private GameResult<Void> checkBalance() {
        GameResult<Void> r = new GameResult<>();
        if (balance >= 1) {
            affordType = GDPlayTime.Afford.BALANCE;
            return r.success();
        }
        return r.fail();
    }

    /**
     * 检测付费购买是否可用(如果有就购买)
     */
    public GameResult<Void> checkBuy(Role role, int funcId) {
        GameResult<Void> r;
        r = checkBuy(role, funcId, GDPlayTime.Afford.PRIVILEGE);
        if (r.ok()) {
            return r;
        }
        if (!r.ok()&& r.code==GDPlayTime.CONSUME_ERROR_CODE){
            return r;
        }
        r = checkBuy(role, funcId, GDPlayTime.Afford.ACTIVITY);
        if (r.ok()) {
            return r;
        }
        r = checkBuy(role, funcId, GDPlayTime.Afford.BASE);
        if (r.ok()) {
            return r;
        }
        return r;
    }

    /**
     * 检测各种付费购买是否可用
     */
    private GameResult<Void> checkBuy(Role role, int funcId, byte affordType) {
        GameResult<Void> r = new GameResult<>();
        int available;
        switch (affordType) {
            case GDPlayTime.Afford.BASE:
                available = getBasicBuyTimes(role, funcId);
                break;
            case GDPlayTime.Afford.PRIVILEGE:
                available = getPrivilageBuyTimes(role, funcId);
                break;
            default:
                available = 0;
        }
        Integer use = buyTimes.get(affordType);
        if (use == null) {
            use = 0;
        }
        if (use >= available) {
            if (funcId==GDFunc.QUICK_FIGHT){
                return r.fail("快速补给次数不足");
            }
            return r.fail("挑战次数不足");
        }
        // 如果有次数就尝试购买
        r = checkAfford(role, funcId, use);
        if (r.ok()) {
            buyTimes.put(affordType, use + 1);
            balance++;
            this.affordType = GDPlayTime.Afford.BALANCE;
        }
        return r;
    }

    /**
     * 获取已经购买的次数
     */
    @JsonIgnore
    public int getBuyTime() {
        int buyTime = 0;
        for (int num : buyTimes.values()) {
            buyTime += num;
        }
        return buyTime;
    }

    /**
     * 检测能否支付起购买次数
     */
    protected GameResult<Void> checkAfford(Role role, int funcId, int use) {
        GameResult<Void> r = new GameResult<>();
        switch (funcId) {
            case GDFunc.QUICK_FIGHT:
                FbBuyConsumeRow consumeRow1 = role.getGame().table.fbBuy.consume.getConsumeRow(funcId, getBuyTime());
                if (consumeRow1 == null) {
                    return r.fail("快速作战消耗配置错误");
                }
                MixRes consume1 = new MixRes(consumeRow1.consumeStr);
                consume1.addList(new MixRes(consumeRow1.extraConsumeStr).multiply(getBuyTime()));
                EcResult<MixResItem> consumeRes1 = consume1.consume(role, null);
                if (!consumeRes1.ok()) {
                    r.fail("碎钻数量不足");
                    r.code = GDPlayTime.CONSUME_ERROR_CODE;
                    return r;
                }
                break;
            default:
                // 以后新的副本功能的购买配置默认读 副本购买配置表
                FbBuyConsumeRow consumeRow = role.getGame().table.fbBuy.consume.getConsumeRow(funcId, use);
                if (consumeRow == null) {
                    return r.fail("副本消耗配置错误");
                }
                MixRes consume = new MixRes(consumeRow.consumeStr);
                consume.addList(new MixRes(consumeRow.extraConsumeStr).multiply(getBuyTime()));
                EcResult<MixResItem> consumeRes = consume.consume(role, null);
                if (!consumeRes.ok()) {
                    return r.fail(consumeRes.message);
                }
                break;
        }
        return r.success();
    }

    public EcResult<Void> checkFreeAndBalance(Role role, int funcId) {
        EcResult<Void> r = checkFree(role, funcId);
        if (r.ok()) {
            return r;
        }
        r = checkBalance();
        if (r.ok()) {
            return r;
        }
        return r.fail("挑战次数不足");
    }

    /**
     * 获取基础免费挑战次数
     */
    @JsonIgnore
    protected int getBasicFreeTimes(Role role, int funcId) {
        if (role == null || funcId <= 0) {
            return 0;
        }
        int freeTime;
        switch (funcId) {
            default:
                freeTime = role.getGame().table.fbBuy.config.getFreeTime(funcId);
                break;
        }
        return freeTime;
    }

    /**
     * 根据特权获取免费次数
     */
    public int getPrivilegeFreeTimes(Role role, int funcId) {
        int freeTime = 0;
        // 特权加成
        switch (funcId) {
            case GDFunc.QUICK_FIGHT:
                boolean checkValied = role.getPay().tradeMall.privilegeMall.checkValied(GDPrivilege.Type.QUICK_FIGHT);
                if (checkValied){
                    freeTime = GDPrivilege.QUICK_FIGHT_ADD_FREE_TIMES;
                }
            default:
                break;
        }
        return freeTime;
    }

    /**
     * 根据特权获取免费次数
     */
    public int getActivityFreeTimes(Role role, int funcId) {
        int freeTime = 0;
        // 特权加成
        switch (funcId) {
            case GDFunc.QUICK_FIGHT:
                RoleTaskActivity activity = role.getActivity().getEnableActivitySingle(GDFunc.SB_QUICK_FIGHT_TASK);
                if (activity != null) {
                    freeTime = GDAdventure.ACTIVITY_FREE_TIMES;
                }
                break;
            default:
                break;
        }
        return freeTime;
    }

    /**
     * 获取基础可购买次数
     */
    protected int getBasicBuyTimes(Role role, int funcId) {
        int allowBuyTimes = role.getGame().table.vip.base.getExtPlayTimes(funcId, role.getBase().vip);
        if (allowBuyTimes > 0) {
            return allowBuyTimes;
        }
        switch (funcId) {
            default:
                allowBuyTimes = role.getGame().table.fbBuy.config.getBuyTime(funcId);
                break;
        }
        return allowBuyTimes;
    }

    /**
     * 获取特权加成的可购买次数
     */
    protected int getPrivilageBuyTimes(Role role, int funcId) {
        int allowBuyTimes = 0;
        switch (funcId) {
            case GDFunc.QUICK_FIGHT:
                boolean checkValied = role.getPay().tradeMall.privilegeMall.checkValied(GDPrivilege.Type.QUICK_FIGHT);
                if (checkValied){
                    allowBuyTimes = GDPrivilege.QUICK_FIGHT_ADD_BUY_TIMES;
                }
                break;
            default:
                break;
        }
        return allowBuyTimes;
    }

    /**
     * 获取特权加成的可购买次数
     */
    protected int getActivityBuyTimes(Role role, int funcId) {
        int allowBuyTimes = 0;
        switch (funcId) {
            case GDFunc.QUICK_FIGHT:
                RoleTaskActivity activity = role.getActivity().getEnableActivitySingle(GDFunc.SB_QUICK_FIGHT_TASK);
                if (activity != null){
                    allowBuyTimes = GDAdventure.ACTIVITY_BUY_TIMES;
                }
                break;
            default:
                break;
        }
        return allowBuyTimes;
    }
}
